package com.mincko.minckotest.server;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.appengine.api.blobstore.BlobInfo;
import com.google.appengine.api.blobstore.BlobInfoFactory;
import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
import com.google.appengine.api.files.AppEngineFile;
import com.google.appengine.api.files.FileService;
import com.google.appengine.api.files.FileServiceFactory;
import com.google.appengine.api.files.FileWriteChannel;
import com.google.appengine.api.images.Composite;
import com.google.appengine.api.images.Image;
import com.google.appengine.api.images.ImagesService.OutputEncoding;
import com.google.appengine.api.images.ImagesServiceFactory;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.images.Transform;
import com.google.gson.Gson;
public class Upload extends HttpServlet {
private BlobstoreService blobstoreService = BlobstoreServiceFactory
.getBlobstoreService();
private Integer targetWidth = 200;
private Integer targetHeight = 200;
private String status = ""; // to indicate to the client wether the image is
// successful or not. 0=success, 1=Step1,
// 2=Step2, 3=Step3
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
Map<String, BlobKey> blobs = blobstoreService.getUploadedBlobs(req);
BlobKey blobKey = blobs.get("photoimg");
String width = req.getParameter("width");
String height = req.getParameter("height");
String jsonRet = null;
if (width == null) { // first time
BlobInfo info = new BlobInfoFactory().loadBlobInfo(blobKey);
ImagesService imagesService = ImagesServiceFactory
.getImagesService();
// Try to fetch image data
byte[] bytes;
try {
bytes = blobstoreService.fetchData(blobKey, 0, info.getSize());
}
catch ( Exception e){
// If not possible, first resize to acceptable size
Image bigImage = ImagesServiceFactory.makeImageFromBlob(blobKey);
Transform initialResize = ImagesServiceFactory.makeResize(1024, 4000);
Image resizedImage = imagesService.applyTransform(initialResize, bigImage);
bytes = resizedImage.getImageData();
}
// We now have an acceptable image for further processing
Image oldImage = ImagesServiceFactory.makeImage(bytes);
Integer intWidth = oldImage.getWidth();
Integer intHeight = oldImage.getHeight();
// step 1: create new image with white background and center image
// in middle; return;
// create new image with white background and center image in
// middle; return;
// trying composite
if (intWidth < targetWidth && intHeight < targetHeight) {
status = "1";
blobKey = getBlobKeyImage(
blobKey,
(setImageMiddle(intWidth, intHeight, oldImage,
imagesService)).getImageData());
// preparing returnJSON
String[] json = { blobKey.getKeyString(), status };
jsonRet = new Gson().toJson(json);
}
// step 2: rescale image to targetWidth
else if (intWidth > targetWidth) {
// if ( true) {
Transform resize = ImagesServiceFactory.makeResize(targetWidth,
4000);
Image newImage = imagesService.applyTransform(resize, oldImage);
// getting the new height
intHeight = newImage.getHeight();
intWidth = newImage.getWidth();
if (intHeight > targetHeight) { // step3: cropping the image
status = "3";
blobKey = getBlobKeyImage(blobKey, newImage.getImageData());
String[] json = { blobKey.getKeyString(), status,
targetWidth.toString(), targetHeight.toString(),
intWidth.toString(), intHeight.toString() };
jsonRet = new Gson().toJson(json);
} else { // make the image middle
status = "1";
blobKey = getBlobKeyImage(
blobKey,
(setImageMiddle(intWidth, intHeight, oldImage,
imagesService)).getImageData());
String[] json = { blobKey.getKeyString(), status };
jsonRet = new Gson().toJson(json);
}
} else if (intHeight > targetHeight) { // step3: cropping the image
status = "3";
String[] json = { blobKey.getKeyString(), status,
targetWidth.toString(), targetHeight.toString(),
intWidth.toString(), intHeight.toString() };
jsonRet = new Gson().toJson(json);
} else { // show the image, good, just show the image
status = "0";
String[] json = { blobKey.getKeyString(), status };
jsonRet = new Gson().toJson(json);
}
}
// return to client
res.setContentType("application/json");
res.setCharacterEncoding("utf-8");
res.getWriter().write(jsonRet);
}
/* set image to middle with white bg */
private Image setImageMiddle(Integer intWidth, Integer intHeight,
Image oldImage, ImagesService imagesService) {
List composites = new ArrayList();
// bg image, might not required since the background already white.
// Image bgImage =
// ImagesServiceFactory.makeImage(getImageBytes("/WEB-INF/images/background.png"));
// Composite c = ImagesServiceFactory.makeComposite(bgImage,0,0,(float)
// 1.0, Composite.Anchor.TOP_LEFT);
// composites.add(c);
// image in middle
int offsetWidth = 0;
int offsetHeight = 0;
if (targetWidth - intWidth > 0)
offsetWidth = (targetWidth - intWidth) / 2;
if (targetHeight - intHeight > 0)
offsetHeight = (targetHeight - intHeight) / 2;
Composite c2 = ImagesServiceFactory.makeComposite(oldImage,
offsetWidth, offsetHeight, (float) 1.0,
Composite.Anchor.TOP_LEFT);
composites.add(c2);
return (imagesService.composite(composites, targetWidth, targetHeight,
0, OutputEncoding.PNG));
}
/* to store and return the blobkey */
private BlobKey getBlobKeyImage(BlobKey blobKey, byte[] data)
throws IOException {
FileService fileService = FileServiceFactory.getFileService();
AppEngineFile file = fileService.createNewBlobFile("image/jpg");
FileWriteChannel writeChannel = fileService
.openWriteChannel(file, true);
// This time we write to the channel directly
writeChannel.write(ByteBuffer.wrap(data));
// Now finalize
writeChannel.closeFinally();
if (blobKey != null)
try {
deleteBlobKey(blobKey);
} catch (IOException e) {
// some error in deleting blob, google app issue
}
// Now read from the file using the Blobstore API
return (BlobKey) fileService.getBlobKey(file);
}
private byte[] getImageBytes(String imagePath) throws IOException {
ServletContext context = getServletContext();
InputStream is = context.getResourceAsStream(imagePath);
final File file = new File(context.getRealPath(imagePath));
long length = file.length();
byte[] bytes = new byte[(int) length];
// Read in the bytes
int offset = 0;
int numRead = 0;
while (offset < bytes.length
&& (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("Could not completely read file "
+ file.getName());
}
// Close the input stream and return bytes
is.close();
return bytes;
}
private void deleteBlobKey(BlobKey blobKey) throws IOException {
// lbe: uncommented this for the time being due to errors.
// blobstoreService.delete(blobKey);
}
}